import 'dart:io';

import 'package:adaptive_dialog/adaptive_dialog.dart';

import 'package:get/get.dart';
import 'package:sainbainu/common/http/exception.dart';
import 'package:sainbainu/common/models/request/content_request.dart';
import 'package:sainbainu/common/models/response/upload_response.dart';
import 'package:sainbainu/common/repositories/common_repository.dart';
import 'package:sainbainu/common/repositories/content_repository.dart';
import 'package:sainbainu/common/services/ali_oss.dart';
import 'package:sainbainu/common/utils/compress.dart';
import 'package:sainbainu/common/utils/loading.dart';
import 'package:sainbainu/common/utils/util.dart';
// android 启用这个
// import 'package:video_compress_plus/video_compress_plus.dart';
// ios 启用这个
import 'package:video_compress/video_compress.dart';
import 'package:wechat_assets_picker/wechat_assets_picker.dart';

typedef UploadFn = Future<String> Function();

// 创建一个包含 Future 和标识的类
class UploadTask {
  final UploadFn future;
  final String type;

  UploadTask(this.future, this.type);
}

/// 全局内容发布控制器
class PublishService extends GetxController {
  static PublishService get to => Get.find();

  final CommonRepository _commonRepository;
  final ContentRepository _contentRepository;

  PublishService(this._commonRepository, this._contentRepository);

  /// 是否显示
  bool _show = false;
  get show => _show;

  /// 上传进度
  final _progress = 0.obs;
  int get progress => _progress.value;

  /// 文本
  String _text = '';
  String get text => _text;

  /// 图片
  List<AssetEntity> _images = [];
  List<AssetEntity> get images => _images;

  /// 图片地址
  List<String> _imageUrls = [];

  /// 视频
  AssetEntity? _video;
  AssetEntity? get video => _video;

  /// 视频地址
  String? _videoUrl;

  /// 录音
  String? _audio;

  /// 语音时长
  Duration? _audioDuration;

  /// 音频地址
  String? _audioUrl;

  /// 链接
  String? _link;

  /// 小组ID
  int? _groupId;

  /// 排序
  List<String> _orderableFormTypes = [];

  /// 是否已发布（监听此值 跳转到关注页）
  var isPublished = false.obs;

  /// ************************************************
  ///
  /// 显示或隐藏
  _handleShowOrHide(bool show) {
    _show = show;
    update();
  }

  setIsPublished(value) {
    isPublished.value = value;
  }

  /// 发布
  onPublish({
    required String text,
    required List<AssetEntity> images,
    AssetEntity? video,
    String? audio,
    Duration? audioDuration,
    String? link,
    int? groupId,
    required List<String> orderableFormTypes,
  }) {
    _text = text;
    _images = images;
    _video = video;
    _audio = audio;
    _audioDuration = audioDuration;
    _link = link;
    _groupId = groupId;
    _orderableFormTypes = orderableFormTypes;
    // 但凡有一个媒体文件 则进行上传并显示进度
    if (images.isNotEmpty || video != null || audio != null) {
      _handleShowOrHide(true);
      _uploadTask();
    } else {
      _handleSubmit();
    }
  }

  /// 上传任务
  _uploadTask() async {
    // 上传任务列表 包含图片、视频、音频
    List<UploadTask> uploadTaskList = [];
    // 上传进度
    int videoProgress = 0;
    int audioProgress = 0;
    List<int> imageProgressList = [];

    /// 计算进度
    void calcProgress() {
      int sum = videoProgress + audioProgress;
      for (var p in imageProgressList) {
        sum += p;
      }
      var p = (sum / uploadTaskList.length * 100).toInt();
      if (_progress.value != p) {
        _progress.value = p;
      }
    }

    /// 收集进度
    void addProgress(int p, String type, [int index = 0]) {
      switch (type) {
        case 'video':
          videoProgress = p;
          break;
        case 'audio':
          audioProgress = p;
          break;
        case 'image':
          imageProgressList[index] = p;
          break;
      }
      calcProgress();
    }

    if (_images.isNotEmpty) {
      // AssetEntity 转 file 对象
      List<File> fileList = await Util.assetEntityToFiles(_images);
      // 批量压缩
      fileList = await CompressUtil().compressImages(
        CompressImagesOptions(fileList),
      );
      for (var i = 0; i < fileList.length; i++) {
        // 图片上传进度数组的占位
        imageProgressList.add(0);
        var file = fileList[i];
        uploadTaskList.add(
          UploadTask(
            () => _handleUpload(
              file,
              UploadMediaType.image,
              (p) => addProgress(p, 'image', i),
            ),
            'image',
          ),
        );
      }
    }
    if (_video != null) {
      var videoFiles = await Util.assetEntityToFiles([_video!]);
      if (videoFiles.isNotEmpty) {
        var videoFile = await _compressVideo(videoFiles[0]);
        uploadTaskList.add(
          UploadTask(
            () => _handleUpload(
              videoFile,
              UploadMediaType.video,
              (p) => addProgress(p, 'video'),
            ),
            'video',
          ),
        );
      }
    }
    if (_audio != null) {
      var audioFile = File(_audio!);
      uploadTaskList.add(
        UploadTask(
          () => _handleUpload(
            audioFile,
            UploadMediaType.audio,
            (p) => addProgress(p, 'audio'),
          ),
          'audio',
        ),
      );
    }

    // 上传任务中取 future
    List<Future<String>> uploadFutureList =
        uploadTaskList.map((task) => task.future()).toList();

    try {
      // 统一上传
      var urls = await Future.wait<String>(uploadFutureList);

      for (int i = 0; i < urls.length; i++) {
        String url = urls[i];
        String type = uploadTaskList[i].type;

        switch (type) {
          case 'image':
            _imageUrls.add(url);
            break;
          case 'video':
            _videoUrl = url;
            break;
          case 'audio':
            _audioUrl = url;
            break;
        }
      }
      _handleShowOrHide(false);
      _handleSubmit();
    } on CustomHttpException catch (e) {
      LoadingUtil.showError(e.message);
      _handleShowOrHide(false);
      _handleReset();
    }
  }

  /// 压缩视频
  Future<File> _compressVideo(File file) async {
    MediaInfo? info = await VideoCompress.compressVideo(
      file.path,
      quality: VideoQuality.MediumQuality,
      deleteOrigin: true,
    );
    VideoCompress.dispose();
    if (info != null) {
      return File(info.path!);
    }
    return file;
  }

  /// 上传
  Future<String> _handleUpload(
    File file,
    UploadMediaType mediaType,
    void Function(int p) onProgress,
  ) async {
    UploadResponse res = await AliOssService.to.upFile(
      file.path,
      mediaType: mediaType,
      onSendProgress: (count, total) {
        onProgress(count ~/ total);
      },
    );
    return res.url;
  }

  /// 提交
  void _handleSubmit() async {
    try {
      var contentRequest = ContentRequest(
        text: _text,
        groupId: _groupId,
        image: _imageUrls.join(','),
        video: _videoUrl,
        audio: _audioUrl,
        audioDuration: _audioDuration == null ? 0 : _audioDuration!.inSeconds,
        link: _link,
        contentSort: _orderableFormTypes.join(','),
      );
      await _contentRepository.create(contentRequest);
      LoadingUtil.showSuccess('发布成功');
      _handleReset();
      setIsPublished(true);
    } on CustomHttpException catch (e) {
      final OkCancelResult res = await showOkCancelAlertDialog(
        context: Get.context!,
        title: '发布失败',
        message: e.message,
        okLabel: '重试',
        cancelLabel: '取消',
        style: AdaptiveStyle.iOS,
      );
      if (res == OkCancelResult.ok) {
        _handleSubmit();
      } else if (res == OkCancelResult.cancel) {
        Get.back();
        _handleReset();
      }
    } catch (e) {
      LoadingUtil.showError('发布失败了');
      _handleReset();
    }
  }

  /// 清空
  void _handleReset() {
    _progress.value = 0;
    _text = '';
    _images = [];
    _imageUrls = [];
    _video = null;
    _videoUrl = null;
    _audio = null;
    _audioDuration = null;
    _audioUrl = null;
    _link = null;
    _groupId = null;
    _orderableFormTypes = [];
  }

  @override
  void onInit() {
    super.onInit();
  }

  @override
  void onReady() {
    super.onReady();
  }

  @override
  void onClose() {
    super.onClose();
  }
}
